<?php
// +----------------------------------------------------------------------
// | 双擎码防伪溯源系统 [ 致力于通过产品和服务，帮助商家开启标准化全链路商品溯源 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2009~2024 https://www.sqm.la All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件，不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 双擎科技 <yjw@sqm.la>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace think\admin\extend;

use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\Writer\PngWriter;

class QrCodeExtend
{
    /**
     * 生成彩色二维码
     * 使用方法：
     * @param string $data 二维码内容
     * @param int $gridSize 二维码平分为多少格[4,9,16]
     * @param array $colors 颜色[[255, 0, 0],[0, 255, 0],[0, 0, 255],[255, 255, 0]]
     * @return void
     */
    public static function generateColoredQrCode(string $data, int $gridSize = 4, array $colors = [])
    {
        // 生成二维码
        $qrCode = Builder::create()
            ->writer(new PngWriter())
            ->data($data)
            ->size(300)
            ->margin(10)
            ->build();

        // 获取二维码图像资源
        $image = imagecreatefromstring($qrCode->getString());
        $width = imagesx($image);
        $height = imagesy($image);

        // 计算每一格的宽度和高度
        $gridWidth = round($width / sqrt($gridSize));
        $gridHeight = round($height / sqrt($gridSize));

        // 定义颜色
        $colorAllocations = [];
        foreach ($colors as $color) {
            if (is_string($color) && preg_match('/^#([a-fA-F0-9]{3}){1,2}$/', $color)) {
                // 如果是16进制颜色代码，转换为RGB
                $rgb = self::hexToRgb($color);
                $colorAllocations[] = imagecolorallocate($image, $rgb['r'], $rgb['g'], $rgb['b']);
            } elseif (is_array($color) && count($color) === 3 && is_int($color[0]) && is_int($color[1]) && is_int($color[2])) {
                // 如果是RGB值，直接使用
                $colorAllocations[] = imagecolorallocate($image, $color[0], $color[1], $color[2]);
            }
        }

        // 遍历每个像素，将黑色像素替换为指定颜色
        for ($x = 0; $x < $width; $x++) {
            for ($y = 0; $y < $height; $y++) {
                $rgb = imagecolorat($image, $x, $y);
                $r = ($rgb >> 16) & 0xFF;
                $g = ($rgb >> 8) & 0xFF;
                $b = $rgb & 0xFF;

                // 如果像素是黑色，则替换为指定颜色
                if ($r == 0 && $g == 0 && $b == 0) {
                    $gridX = intval($x / $gridWidth);
                    $gridY = intval($y / $gridHeight);
                    $colorIndex = ($gridX + $gridY * sqrt($gridSize)) % count($colorAllocations);
                    imagesetpixel($image, $x, $y, $colorAllocations[$colorIndex]);
                }
            }
        }

        // 输出图像
        header('Content-Type: image/png');
        ob_clean(); // 清除缓冲区
        imagepng($image);
        imagedestroy($image);
        exit; // 确保没有其他内容输出
    }

    /**
     * 16进制颜色转rgb
     * @param string $hex
     * @param array $default
     * @return array|int[]
     */
    public static function hexToRgb(string $hex, array $default = array('r' => 0, 'g' => 0, 'b' => 0)): array
    {
        // 去除可能存在的 # 符号
        $hex = ltrim($hex, '#');

        // 检查16进制颜色代码的长度
        if (strlen($hex) == 3) {
            // 如果是3位数的16进制颜色代码，将其扩展为6位数
            $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
        } elseif (strlen($hex) != 6) {
            // 如果不是6位数的16进制颜色代码，返回默认值
            return $default;
        }

        // 将16进制颜色代码转换为RGB值
        return array(
            'r' => hexdec(substr($hex, 0, 2)),
            'g' => hexdec(substr($hex, 2, 2)),
            'b' => hexdec(substr($hex, 4, 2))
        );
    }
}